﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Media;

namespace SuperFrame.Charts
{
    public class SplineCurveHelper
    {
        public static List<Point> ControlPoint(PointCollection list, int n)
        {
            List<Point> point = new List<Point>();
            point.Add(new Point());
            point.Add(new Point());

            if (n == 0)
            {
                point[0] = list[0];
            }
            else
            {
                point[0] = Average(list[n - 1], list[n]);
            }

            if (n == list.Count - 1)
            {
                point[1] = list[list.Count - 1];
            }
            else
            {
                point[1] = Average(list[n], list[n + 1]);
            }
            Point ave = Average(point[0], point[1]);
            Point sh = Sub(list[n], ave);
            point[0] = Mul(Add(point[0], sh), list[n], 0.6);
            point[1] = Mul(Add(point[1], sh), list[n], 0.6);
            return point;

        }
        //计算平均
        static Point Average(Point x, Point y)
        {
            return new Point((x.X + y.X) / 2, (x.Y + y.Y) / 2);
        }
        //计算和
        static Point Add(Point x, Point y)
        {
            return new Point(x.X + y.X, x.Y + y.Y);
        }
        //计算相差
        static Point Sub(Point x, Point y)
        {
            return new Point(x.X - y.X, x.Y - y.Y);
        }
        //计算倍数
        static Point Mul(Point x, Point y, double d)
        {
            Point temp = Sub(x, y);
            temp = new Point(temp.X * d, temp.Y * d);
            temp = Add(y, temp);
            return temp;
        }
    }



    /// <summary>
    /// 贝塞尔Spline
    /// </summary>
    public static class BezierSpline
    {
        /// <summary>
        /// 有开放式的贝塞尔样条曲线控制点。
        /// </summary>
        /// <param name="knots">输入结Bezier样条点。</param>
        /// <param name="firstControlPoints">输出第一个控制点数组的结，长度-1长度。</param>
        /// <param name="secondControlPoints">输出第二个控制点数组的结。长度-1长度。</param>
        /// <exception cref="ArgumentNullException"><paramref name="knots"/>参数必须不为空。 </exception>
        /// <exception cref="ArgumentException"><paramref name="knots"/>数组必须至少包含两点。 </exception>
        public static void GetCurveControlPoints(Point[] knots, out Point[] firstControlPoints, out Point[] secondControlPoints)
        {
            if (knots == null)
                throw new ArgumentNullException("knots");
            int n = knots.Length - 1;
            if (n < 1)
                throw new ArgumentException("至少需要两个结点", "knots");
            if (n == 1)
            { // 特殊情况：Bezier曲线应该是一条直线。
                firstControlPoints = new Point[1];
                // 3P1 = 2P0 + P3
                firstControlPoints[0].X = (2 * knots[0].X + knots[1].X) / 3;
                firstControlPoints[0].Y = (2 * knots[0].Y + knots[1].Y) / 3;

                secondControlPoints = new Point[1];
                // P2 = 2P1 – P0
                secondControlPoints[0].X = 2 * firstControlPoints[0].X - knots[0].X;
                secondControlPoints[0].Y = 2 * firstControlPoints[0].Y - knots[0].Y;
                return;
            }

            // 第一条贝塞尔控制点计算
            // 右手侧向量
            double[] rhs = new double[n];

            // 设置右手侧X值
            for (int i = 1; i < n - 1; ++i)
                rhs[i] = 4 * knots[i].X + 2 * knots[i + 1].X;
            rhs[0] = knots[0].X + 2 * knots[1].X;
            rhs[n - 1] = (8 * knots[n - 1].X + knots[n].X) / 2.0;
            // 获得第一个控制点的x值
            double[] x = GetFirstControlPoints(rhs);

            // 设置右手边Y值
            for (int i = 1; i < n - 1; ++i)
                rhs[i] = 4 * knots[i].Y + 2 * knots[i + 1].Y;
            rhs[0] = knots[0].Y + 2 * knots[1].Y;
            rhs[n - 1] = (8 * knots[n - 1].Y + knots[n].Y) / 2.0;
            // 获得第一个控制点的y值
            double[] y = GetFirstControlPoints(rhs);

            // 填充输出阵列
            firstControlPoints = new Point[n];
            secondControlPoints = new Point[n];
            for (int i = 0; i < n; ++i)
            {
                // 第一个控制点
                firstControlPoints[i] = new Point(x[i], y[i]);
                // 第二个控制点
                if (i < n - 1)
                    secondControlPoints[i] = new Point(2 * knots[i + 1].X - x[i + 1], 2 * knots[i + 1].Y - y[i + 1]);
                else
                    secondControlPoints[i] = new Point((knots[n].X + x[n - 1]) / 2, (knots[n].Y + y[n - 1]) / 2);
            }
        }

        /// <summary>
        /// 解决了一个三对角一坐标系（X或Y）第一次Bezier控制点。
        /// </summary>
        /// <param name="rhs">右手侧向量。</param>
        /// <returns>解向量。</returns>
        private static double[] GetFirstControlPoints(double[] rhs)
        {
            int n = rhs.Length;
            double[] x = new double[n]; // 解向量。
            double[] tmp = new double[n]; // 临时工作区。

            double b = 2.0;
            x[0] = rhs[0] / b;
            for (int i = 1; i < n; i++) // 分解与前向置换。
            {
                tmp[i] = 1 / b;
                b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
                x[i] = (rhs[i] - x[i - 1]) / b;
            }
            for (int i = 1; i < n; i++)
                x[n - i - 1] -= tmp[n - i] * x[n - i]; // 回代.
            return x;
        }
    }

    /// <summary>
    /// 风格资源
    /// </summary>
    public static class Themes
    {
        /// <summary>
        /// 将资源字典合并到当前资源中
        /// </summary>
        /// <param name="AddUrl">空则为系统默认</param>
        public static void SetResource(string AddUrl)
        {
            if (string.IsNullOrEmpty(AddUrl)) AddUrl = "/SuperFrame.Charts;component/Themes/Styles.xaml";
            ResourceDictionary resourceAdd = (ResourceDictionary)Application.LoadComponent(new Uri(AddUrl, UriKind.Relative));
            //Application.Current.Resources.MergedDictionaries.Remove(resourceRemove);
            Application.Current.Resources.MergedDictionaries.Add(resourceAdd);
        }


        private static List<Brush> metroBrushes;
        /// <summary>
        /// 图形颜色资源
        /// </summary>
        public static List<Brush> MetroBrushes
        {
            get
            {
                if (metroBrushes == null)
                {
                    metroBrushes = new List<Brush>();

                    metroBrushes.Add(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#d96c6c")));
                    metroBrushes.Add(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#d98f45")));
                    metroBrushes.Add(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#e6d27a")));
                    metroBrushes.Add(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#41b3a0")));
                    metroBrushes.Add(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#0092cc")));
                    metroBrushes.Add(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#34c0d9")));
                    metroBrushes.Add(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#b37da2")));

                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 0x1B, 0xA1, 0xE2)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 160, 80, 0)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0x00, 0x00)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 0xA2, 0xC1, 0x39)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 0xD8, 0x00, 0x73)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 230, 113, 84)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 240, 150, 9)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 27, 161, 226)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 0x33, 0x99, 0x33)));
                    metroBrushes.Add(new SolidColorBrush(Color.FromArgb(0xFF, 0, 171, 169)));
                }
                return metroBrushes;
            }
            set { metroBrushes = value; }
        }

        public static Brush GetRandomColor()
        {
            Random rand1 = new Random();
            return new SolidColorBrush(Color.FromRgb(Convert.ToByte(rand1.Next(0, 255)), Convert.ToByte(rand1.Next(0, 255)), Convert.ToByte(rand1.Next(0, 255))));
        }

    }

    public static class Tools
    {
        public static double GetStrFontWidth(string str)
        {
            double tmpWidth = 0;
            try
            {
                FormattedText ft = new FormattedText(str, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("微软雅黑"), 12, Brushes.Black);
                tmpWidth = ft.Width;
            }
            catch (Exception) { }
            return tmpWidth;
        }


    }
}
